#include <cassert>
#include <cstdio>
#include <dspSimulator/targetMachine/dspMachine.h>
#include <simulator/elf/elfLoader.h>
#include <simulator/elf/elf32/elf32Loader.h>
#include <dspSimulator/dspSimulator/dspSimulator.h>

using namespace std;

int main(int argc, char *argv[]) {
//    assert(argc > 1);
//    shared_ptr<LLVMJit> llvmJit = make_shared<LLVMJit>();
//    shared_ptr<DspMachine> m = make_shared<DspMachine>(llvmJit);
//    loadElfProgram(m, argv[1]);
//    printf("entry: 0x%08X\n", m->getMMU()->getEntry());
//
//    cout << "read bits :" << m->getMMU()->getMemory()->read32(0x8000) << endl;

//    m->getMMU()->getMemory()->write32(0x8000,{0xAAAAAAAA});

//    cout << "read bits :" << m->getMMU()->getMemory()->read32(0x8000) << endl;


    printf("=========================================\n");

//    LLVMJit jit;
//    jit.initializeModule("first-m_module");
//    unique_ptr<llvm::Module> m_module = jit.extraCurModule();
//    shared_ptr<llvm::IRBuilder<>> m_irBuilder = jit.getIrBuilder();
//    m_module->getOrInsertGlobal("a", m_irBuilder->getInt8Ty());
//    LLVMContext *m_llvmContext = jit.getLLVMContext();
//    Type *voidType = Type::getVoidTy(*m_llvmContext);
//    FunctionType *functionType = FunctionType::get(voidType, false);
//    Function *function = Function::Create(functionType, GlobalValue::ExternalLinkage, "HelloFunction", *m_module);
//    BasicBlock *block = BasicBlock::Create(*m_llvmContext, "entry", function);
//    m_irBuilder->SetInsertPoint(block);
//
//    m_module->print(llvm::errs(), nullptr);

    printf("========================================================\n");
//
//    std::bitset<32> src(0b10111100);
//    std::bitset<5> target(0b01111);
//    std::cout << "check bits : " << checkBits<5>(src, 3, target) << std::endl;
//    std::cout << "get bits : " << getBits<4>(src,3) << std::endl;
//    std::cout << src << endl;
//    cout << src.to_ulong() << endl;

    printf("========================================================\n");
//    shared_ptr<LLVMJit> llvmJit = make_shared<LLVMJit>();
//    shared_ptr<DspMachine> dspMachine = make_shared<DspMachine>();
////    loadInstFromTxt(dspMachine,"../instDir/inst.txt");
//    loadElfProgram(dspMachine,argv[1]);
//    shared_ptr<DSPSimulator> dspSimulator1 = make_shared<DSPSimulator>(llvmJit,dspMachine);
//    dspSimulator1->start();
    std::shared_ptr<TargetMachine> dspMachine = make_shared<DspMachine>();
    std::shared_ptr<InstFetcher> dspInstFetch = make_shared<DspInstFetcher>(dspMachine);
    std::shared_ptr<LLVMJit> llvmJit = make_shared<LLVMJit>();
    std::shared_ptr<DSPSimulator> dspSimulator = make_shared<DSPSimulator>(dspMachine, dspInstFetch, llvmJit);
    auto memory = dspMachine->getMMU()->getMemory();
    std::shared_ptr<ELFLoader> elfLoader = make_shared<ELF32Loader>();
    u64 entry = elfLoader->loadELFProgramIntoMemory("/home/zengao/Desktop/dsp-sim/for.out", memory);
    dspMachine->getRegisters()->getReg32ByName("pc")->updateData(entry);
    dspSimulator->addAllInstructionProto();
    dspSimulator->run();
    return 0;
}